#include "imagedocument.h"
#include "ip.h"
#include <QTextStream>

ImageDocument::ImageDocument()
{
}

ParseThread* ImageDocument::parseImage(const cv::Mat &img)
{
  m_thread = new ParseThread(this, img);
  //connect(m_thread, SIGNAL(parseLine(int)), this, SIGNAL(parseLine(int)));
  m_thread->start();
  return m_thread;
}

ParseThread* ImageDocument::createThread(const cv::Mat &img)
{
  m_thread = new ParseThread(this, img);
  return m_thread;
}

void ImageDocument::parseImage()
{
  if (m_thread)
    m_thread->start();
}

void ImageDocument::moveCurrent(int d)
{
  if (d <-1 || d > 1) return;
  if (d == -1)
  {
    if (m_curChar > 0) m_curChar--;
    else
      if (m_curLine > 0)
      {
        m_curLine--;
        m_curChar = m_lines[m_curLine].chars.size()-1;
      }
  }
  else
  {
    if (m_curChar < m_lines[m_curLine].chars.size()-1)
      m_curChar++;
    else
      if (m_curLine < m_lines.size()-1)
      {
        m_curLine++;
        m_curChar = 0;
      }
  }
}

ParseThread::ParseThread(ImageDocument* imgDoc, const cv::Mat &img)
  : m_imgDoc(imgDoc), m_img(img)
{
}

void ParseThread::run()
{
  // Detect lines
  m_imgDoc->lines().clear();
  detectLines();
  detectCharacters();
  m_imgDoc->resetCurrent();
}

void ParseThread::detectLines()
{
  bool empty = true, prev_empty = true;
  int startLine = -1, endLine = 0/*, startSeparator = 0, endSeparator = 0*/;
  int minHeight = 9;
  for (int i = 0; i < m_img.rows; i++)
  {
    if (i%50 == 0) emit parseLine(i);
    empty = isLineEmpty(i);
    if (!empty)
    {
      if (prev_empty) startLine = i;
    }
    else
    {
      if (!prev_empty)
      {
        endLine = (startLine > i-1) ? startLine : i-1;
        if (startLine != -1 && startLine+minHeight <= endLine)
        {
          emit detectLine(startLine, endLine);
          m_imgDoc->lines() << Line(1, startLine, endLine);
        }
      }
      startLine = -1;
    }
    prev_empty = empty;
  }
}

struct Fragment {
  int start, end;
  Fragment(int s = 0, int e = 0) : start(s), end(e) {}
  int width() const { return end-start+1; }
};

void ParseThread::detectCharacters()
{
  QVector<Line>& lines = m_imgDoc->lines();
  for (int i = 0; i < lines.size(); i++)
  {
    if (lines[i].type == 0) continue;
    QVector<Fragment> fragments;
    int r_s = lines[i].start, r_e = lines[i].end;
    QTextStream(stdout) << "line = " << r_s << " " << r_e << endl;
    int c_s = -1, c_e = 0;
    int empty = true, prev_empty = true;
    // detect fragment
    for (int j = 0; j < m_img.cols; j++)
    {
      empty = isColEmpty(j, r_s, r_e);
      if (!empty && prev_empty) c_s = j;
      if (empty && !prev_empty)
      {
        c_e = j-1;
        if (c_s <= c_e)
          fragments << Fragment(c_s, c_e);
      }
      prev_empty = empty;
    }
    // merge fragments
    int width = 23;
    for (int f = 0; f < fragments.size(); f++)
    {
      int s = fragments[f].start;
      int f1 = f;
      while (f1 < fragments.size()-1 && fragments[f1+1].end-s+1 < width) f1++;
      lines[i].chars << cv::Rect(s, r_s, fragments[f1].end-s+1, r_e-r_s+1);
      f = f1;
    }
  }
}

bool ParseThread::isLineEmpty(int y)
{
  RGB bk_color(255, 255, 255);
  for (int x = 0; x < this->m_img.cols; x++)
  {
    const RGB& c = IP::getRGB(m_img, y, x);
    if (c != bk_color)
      return false;
  }
  return true;
}

bool ParseThread::isColEmpty(int x, int start, int end)
{
  RGB bk_color(255, 255, 255);
  for (int y = start; y < this->m_img.rows && y <= end; y++)
  {
    const RGB& c = IP::getRGB(m_img, y, x);
    if (c != bk_color)
      return false;
  }
  return true;
}
